<script setup lang="ts">
/**
 * 仪表盘
 */
import { onMounted, onUnmounted, ref, useTemplateRef } from 'vue';
import * as echarts from 'echarts';
import chroma from 'chroma-js'; // npm i chroma-js

const boxRef = useTemplateRef<HTMLElement>('boxRef');
let chart: echarts.ECharts;
const initChart1 = () => {
    chart?.dispose();
    const dom = boxRef.value!.querySelector('.chart') as HTMLElement;
    chart = echarts.init(dom, null, {
        renderer: 'svg',
        width: dom.offsetWidth,
        height: dom.offsetHeight,
    });
    onUnmounted(() => {
        chart.dispose();
    });
};

// 生成圆锥渐变纹理
function createConicTexture(option: {
    value: number;
    width: number;
    height: number;
    lineNum: number;
    radius: number;
    startAngle: number; // 度，0=正上方
    endAngle: number;
    startColor: string;
    endColor: string;
    lineWidth: number;
}) {
    const {
        value,
        width,
        height,
        lineNum,
        startAngle,
        endAngle,
        radius,
        startColor,
        endColor,
        lineWidth,
    } = option;
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d')!;

    let x = 0;
    let y = 0;

    if (value <= 25) {
        y = radius;
    }
    if (value < 25) {
        x = radius - radius * Math.sin((2 * Math.PI * value) / 100);
    }
    if (value > 25 && value < 50) {
        y = radius - radius * Math.sin((2 * Math.PI * (value - 25)) / 100);
    }

    const cx = width / 2 - x;
    const cy = height / 2 - y;

    const palette = chroma
        .scale([startColor, endColor]) // 起止颜色
        .mode('lab') // 可选：lab 空间更视觉均匀
        .colors(lineNum) as string[]; // 一步拿到色值数组

    // 每段角度
    const angleStep = (endAngle - startAngle) / lineNum;

    for (let i = 0; i < lineNum; i++) {
        const angle = startAngle + i * angleStep;
        const rad = -(angle * Math.PI) / 180; // 0°=顶部
        ctx.strokeStyle = palette[i];
        // 线宽
        ctx.lineWidth = lineWidth;
        ctx.beginPath();
        ctx.moveTo(cx, cy);
        ctx.lineTo(cx + radius * -Math.cos(rad), cy + radius * Math.sin(rad));
        ctx.stroke();
    }

    return canvas;
}

const updateChart = (value: number) => {
    const radius = 80;
    const max = 100;

    const getR = (gapCount: number) => {
        const gap = 10;
        return Math.round(
            (Math.min(chart.getHeight(), chart.getWidth()) / 2) *
                ((radius - gap * gapCount) / 100),
        );
    };
    const option: echarts.EChartsOption = {
        title: {
            text: '内存使用率',
            left: 'left',
        },
        series: [
            // 1 进度条和刻度
            {
                type: 'gauge',
                animation: false,
                startAngle: 270,
                endAngle: -90,
                radius: getR(0),
                // 刻度间隔
                splitNumber: 5,
                min: 0,
                max,
                pointer: {
                    show: false,
                },
                // 渐变刻度
                progress: {
                    show: true,
                    // 不开启切割
                    width: 100,
                    itemStyle: {
                        // 条纹渐变 → 虚线效果
                        color: {
                            image: createConicTexture({
                                value,
                                width: getR(0) * 2,
                                height: getR(0) * 2,
                                lineNum: 100,
                                startAngle: -90,
                                endAngle: 270,
                                radius: getR(0),
                                startColor: 'rgb(104,189,104)', // 道奇蓝
                                endColor:
                                    value < 80
                                        ? 'rgb(0,100,255)'
                                        : 'rgb(255,0,0)', // 青色
                                lineWidth: 2,
                            }),
                            repeat: 'no-repeat',
                        },
                    },
                },
                axisLine: {
                    show: false,
                },
                // 大刻度
                splitLine: {
                    show: false,
                },
                // 小刻度
                axisTick: {
                    show: true,
                    distance: -20,
                    length: 5,
                    lineStyle: {
                        width: 2,
                        // 刻度的颜色
                        color: value < 80 ? '#64a0e3' : '#e19090',
                    },
                },
                axisLabel: {
                    show: false,
                },
                detail: {
                    show: false,
                },
                data: [
                    {
                        value: value,
                        name: 'a',
                    },
                ],
                z: 1,
            },
            // 3 指针
            {
                animation: false,
                type: 'gauge',
                startAngle: 270,
                endAngle: -90,
                radius: '50%',
                max,
                // 大刻度
                splitLine: {
                    show: false,
                },
                progress: {
                    show: false,
                },
                axisLabel: {
                    show: false,
                },
                axisTick: {
                    show: false,
                },
                pointer: {
                    show: true,
                    offsetCenter: [0, '-105%'],
                    icon: 'path://M12.8,0.7L12,40.1H0.7L12.8,0.7z',
                    length: '92%',
                    width: '10%',
                    itemStyle: {
                        color: value < 80 ? '#99c9ff' : '#e19090',
                    },
                },
                detail: {
                    show: false,
                },
                data: [
                    {
                        value: value,
                        name: 'c',
                    },
                ],
                z: 3,
            },
        ] as echarts.SeriesOption,
        graphic: [
            // 2 指针下层的圆盘
            {
                type: 'rect',
                z: 2,
                left: 'center',
                top: 'center',
                shape: { r: getR(1) },
                style: {
                    fill: new echarts.graphic.RadialGradient(0.5, 0.5, 1, [
                        {
                            offset: 0,
                            color: '#ffffff',
                        },
                        { offset: 1, color: '#ff0000' },
                    ]),
                },
            },
            // 4 指针上层的圆盘
            {
                type: 'group',
                left: 'center',
                top: 'center',
                children: [
                    {
                        type: 'circle',
                        left: 'center',
                        top: 'center',
                        z: 4,
                        shape: { r: getR(2) },
                        style: {
                            fill: new echarts.graphic.RadialGradient(
                                0.5,
                                0.5,
                                1,
                                [
                                    {
                                        offset: 0.5,
                                        color: 'rgb(251,253,255)',
                                    },
                                    {
                                        offset: 1,
                                        color: 'rgb(255,255,255)',
                                    },
                                ],
                            ),
                        },
                    },
                    // 5 数值显示
                    {
                        // 数值显示
                        type: 'text',
                        z: 5,
                        left: 'center',
                        top: 'center',
                        style: {
                            fill: 'rgb(110,158,253)',
                            text: value.toFixed(0) + '%',
                            fontSize: 37,
                            // 文字加粗
                            fontWeight: 'bold',
                        },
                    },
                ],
            },
        ],
    };
    chart!.setOption(option);
};

let timer: ReturnType<typeof setTimeout>;
let lastValue = 0;
const updateC = (value: number) => {
    clearInterval(timer);
    if (value === lastValue) return;

    const d = value < lastValue ? -1 : 1;
    const duration = 1000;
    const t = duration / 100;

    timer = setInterval(() => {
        lastValue += d;
        updateChart(lastValue);
        if (lastValue === value) {
            clearInterval(timer);
        }
    }, t);
};
const value = ref(50);

onMounted(() => {
    initChart1();
    updateC(value.value);
});
</script>

<template>
    <div ref="boxRef">
        <input
            type="number"
            v-model="value"
            :min="0"
            :max="100"
            @change="updateC(value)"
        />
        <div class="chart" />
    </div>
</template>

<style lang="scss" scoped>
.chart {
    height: 200px;
    border: solid;
}
</style>
